/**
 * CRUD 饿了么UI适配器。通过Vue安装后使用
 * @author holyhigh
 */
import {size, concat, each, find,
  remove, isDefined, isNull,
  isUndefined} from '@holyhigh/func.js';

import CRUD, {lookupCRUD, crudWarn, crudError} from './index';
import * as packageInfo from '../package.json';

CRUD.install = function(Vue, options) {
  // 使用业务主请求器，避免因跨域或token等导致的异步失败
  if (!options.request) {
    crudError('Cannot find [request] in the installation options');
  }
  CRUD.request = options.request;
  CRUD.prototype.doValidate = function(name) {
    return new Promise((resolve, reject)=>{
      const formVM = this.formVM.$vnode?this.formVM:this.formVM[name];
      if (!formVM) {
        crudError('Cannot find formVM to validate');
        return;
      }
      formVM.validate((valid, object) => {
        if (valid)resolve(true);
        else {
          reject(new Error(JSON.stringify(object)));
        }
      });
    });
  };

  // 注入curd入口。
  // 以此简化在每个使用场景需要引入CRUD的过程
  Vue.mixin({
    beforeCreate() {
      // 具有标记crud的组件认为该组件启用了crud，即可注入$crud属性
      const crud = this.$options.crud;
      const cruds = this.$options.cruds;
      if (crud || cruds) {
        const crudMap = {};
        if (crud) {
          this.$crud = Vue.observable(new CRUD(crud));
          crudMap['default'] = this.$crud;
        } else {
          each(cruds, (v, k) => {
            crudMap[k] = Vue.observable(new CRUD(v));
          });
          this.$cruds = crudMap;
        }

        this.$isCrudEntry = true;

        each(crudMap, (crud) => {
          Object.defineProperty(crud, 'vm', {
            value: this,
            enumerable: false,
          });
        });
      } else

      // el-table托管
      if (this.$vnode &&
        this.$vnode.componentOptions.tag === 'el-table' &&
        isDefined(this.$attrs.crud)
      ) {
        // 查找crud
        const crud = lookupCRUD(this);

        // 1. 绑定
        let rowKey = this.$options.propsData.rowKey;
        if (isUndefined(rowKey)) {
          rowKey = 'id';
          crudWarn('No row-key found that on el-table, set default value "id"');
        }
        crud.table.rowKey = rowKey;
        // 通知绑定
        if (!crud.table.vm) {
          Object.defineProperty(crud.table, 'vm', {
            value: this,
            enumerable: false,
          });
        }

        // 2. 事件
        this.$on('selection-change', (selection) => {
          Vue.set(crud.table, 'selection', concat([], selection));
        });
        this.$on('sort-change', ({column, prop, order}) => {
          // 只控制自定义排序
          if (column.sortable !== 'custom') return;

          const isAsc = isNull(order) ? null : order === 'ascending';
          const item = find(crud.table.orders, (item) => item.column === prop);
          if (item) {
            if (isAsc == null) {
              remove(crud.table.orders, item);
            } else {
              item.asc = isAsc;
            }
          } else {
            if (order != null) {
              crud.table.orders.push({column: prop, asc: isAsc});
            }
          }

          crud.toQuery();
        });
      } else

      // el-tree托管
      if (this.$vnode &&
        this.$vnode.componentOptions.tag === 'el-tree' &&
        isDefined(this.$attrs.crud)
      ) {
        // 查找crud
        const crud = lookupCRUD(this);

        // 1. 绑定
        let nodeKey = this.$options.propsData.nodeKey;
        if (isUndefined(nodeKey)) {
          nodeKey = 'id';
          crudWarn('No node-key found that on el-tree, set default value "id"');
        }
        crud.table.rowKey = nodeKey;
        // 通知绑定
        if (!crud.table.vm) {
          Object.defineProperty(crud.table, 'vm', {
            value: this,
            enumerable: false,
          });
        }

        // 2. 事件
      } else

      // elpagination托管
      if (this.$vnode &&
        this.$vnode.componentOptions.tag === 'el-pagination' &&
        isDefined(this.$attrs.crud)) {
        // 查找crud
        const crud = lookupCRUD(this);

        // 1. 绑定
        // 2. 事件
        this.$on('size-change', (pageSize) => {
          crud.toQuery();
        });
        this.$on('current-change', (currentPage) => {
          crud.toQuery();
        });
      } else

      // elform托管
      if (this.$vnode &&
        this.$vnode.componentOptions.tag === 'el-form' &&
        isDefined(this.$attrs.crud)) {
        // 查找crud
        const crud = lookupCRUD(this.$options.parent);

        // 1. 绑定
        if (crud.formVM) {
          if (crud.formVM.$vnode) {
            const key = crud.formVM.$attrs.name || 'crudForm_0';
            const vm = crud.formVM;
            crud.formVM = {};
            crud.formVM[key] = vm;
          }
          const key = this.$attrs.name || 'crudForm_'+size(crud.formVM);
          crud.formVM[key] = this;
        } else {
          Object.defineProperty(crud, 'formVM', {
            value: this,
            enumerable: false,
            writable: true,
          });
        }
        // 2. 事件
      }
    },
  });

  // welcome info
  const ssAry = [];
  ['220,235,153', '179,208,75', '153,189,37'].forEach((v, i)=>{
    const cu = 'background:rgb('+v+');';
    if (i<2) {
      ssAry[i] = ssAry[5-1-i] = cu;
    } else {
      ssAry[i] = 'color:#fff;'+cu;
    }
  });
  console.info(`%c %c %c CRUD-vue - ${packageInfo.description} | v${packageInfo.version} %c %c `, ...ssAry, '\u{1F4E6} https://gitee.com/holyhigh2/crud-vue');
};

export default CRUD;
